/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package optinsa;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;

/**
 *
 * @author falxa
 */
public class Algo {
    
    public static final int EDD = 1;
    public static final int SPT = 2;
    public static final int LPT = 3;
    public static final int RANDOM = 4;
    
    public Algo()
    {
    }
    
    public Problem parseFile(String path)
    {
        System.out.println("Traitement fichier "+path);
        
        ArrayList<Job> jobs = new ArrayList<>();
        ArrayList<Ressource> ressources = new ArrayList<>();
        
        String line = "";
        String[] splited;
        int nbJobs = 0;
        int nbRess = 0;
        
        try 
        {
            BufferedReader br = new BufferedReader(new FileReader(path));
            
            try 
            {
                line = br.readLine();
                splited = line.split(" +");
                nbJobs = Integer.parseInt(splited[0]);
                nbRess = Integer.parseInt(splited[1]);
                
                for (int i=0; i<nbRess; i++)
                    ressources.add(new Ressource(i));
                
                for (int i=0; i<nbJobs; i++)
                {
                    line = br.readLine();
                    splited = line.split(" +");
                    
                    jobs.add(new Job(i));
                    
                    for (int j=0; j<nbRess*2; j+=2)
                    {
                        int r = Integer.parseInt(splited[j]);
                        int d = Integer.parseInt(splited[j+1]);
                        Task t = new Task(jobs.get(i).getTasks().size(), i, ressources.get(r), d);
                        jobs.get(i).addTask(t);
                    }
                }
                
                // Affichage
                for (int i=0; i<jobs.size(); i++)
                {
                    jobs.get(i).print();
                    jobs.get(i).setDate(0);
                }
                
            } catch (IOException ex) {
                System.out.println("Impossible de lire une ligne");
            }
            
        } catch (FileNotFoundException ex) {
            System.out.println("Impossible de lire le fichier");
        }
        
        return new Problem(jobs, ressources);
    }
    
    public Task priorityTask(ArrayList<Task> tasks, int rule)
    {
        Task t=null, prio=null;
        
        if (tasks.size()>0) prio = tasks.get(0);
        
        for (int i=0; i<tasks.size(); i++)
        {
            t = tasks.get(i);
            
            switch(rule)
            {
                case EDD:
                    if ((t.getEarlydate() + t.getDuration()) < (prio.getEarlydate() + prio.getDuration()))
                        prio = t;
                    break;
                case SPT:
                    if (t.getDuration() < prio.getDuration())
                        prio = t;
                    break;
                case LPT:
                    if (t.getDuration() > prio.getDuration())
                        prio = t;
                    break;
                case RANDOM:
                    Random ran = new Random();
                    int index = ran.nextInt(tasks.size());
                    prio = tasks.get(index);
                    break;
                default:
                    System.out.println("Règle non reconnue");
                    break;
            }
        }
        
        tasks.remove(prio);
        return prio;
    }
    
    
    public Solution gloutonSolver(Problem p, int rule)
    {
        boolean end = false;
        int freeIn, date = 0;
        Task t;
        
        ArrayList<Job> jobs = p.getJobs();
        ArrayList<Task> availableTasks = new ArrayList<>();

        Solution s = new Solution(p.getRessources().size(), p.clone());
        
        while (!end)
        {
            // Etablissement de la liste des tâches executables à la date actuelle
            for (int i=0; i<jobs.size(); i++)
            {
                end = true;
                
                for (int j=0; j<jobs.get(i).getTasks().size(); j++)
                {
                    t = jobs.get(i).getTasks().get(j);

                    // Si la tâche est terminée, on ajoute la suivante à la liste des tâches disponibles et on passe au Job suivant
                    if (!t.isDone())
                    {
                        end = false;
                        availableTasks.add(t);
                        break;
                    }
                }  
            }
            
            // Une fois la liste des tâches disponibles construite
            // On parcourt toute cette liste
            while (availableTasks.size() > 0)
            {
                t = priorityTask(availableTasks, rule);
                Job tjob = jobs.get(t.getJob());

                date = tjob.getDate(); // on voit à quelle date en est le job de cette tâche
                freeIn = t.getRessource().isFreeIn(); // on recupère la date à laquelle la ressource de cette tâche sera disponible
                
                // Si la ressource est disponible avant que la tâche précédente ne soit terminée
                // on démarre la tâche à la date à laquelle la tâche précédente sera terminée
                // sinon on la lance dès que la ressource est disponible
                t.doTask(Math.max(freeIn, date));
                tjob.setDate(t.getDate() + t.getDuration());
                
                s.addSolution(t);
            }
        }
        
        int datemax = s.getDateMax();
        s.printSolution();
        
        return s;
    }
    
    public static void main(String[] args)
    {
        Algo a = new Algo();
        
        Problem ft06, ft10, ft20;
        Solution s06, s10, s20;
        
        ft06 = a.parseFile("data/ft06");
        System.out.println("EVAL JOBS: "+ft06.evaluation());
        s06 = a.gloutonSolver(ft06, EDD);
        System.out.println("DATE MAX GLOUTON: "+s06.getDateMax());
        ft06.displayJobs();
        
        ArrayList<Solution> neigh06 = s06.genNeighbour();
        for (int i=0; i<neigh06.size(); i++)
            System.out.println("Voisin "+i+": "+neigh06.get(i).evalSolution());
        
        /*ft10 = a.parseFile("data/ft10");
        System.out.println("EVAL JOBS: "+ft10.evaluation());
        System.out.println("DATE MAX GLOUTON: "+a.gloutonSolver(ft10, EDD));
        ft10.displayJobs();
        
        ft20 = a.parseFile("data/ft20");
        System.out.println("EVAL JOBS: "+ft20.evaluation());
        System.out.println("DATE MAX GLOUTON: "+a.gloutonSolver(ft20, EDD));
        ft20.displayJobs();*/
    }
    
}
